package com.example.demo.verify.validator;

import com.example.demo.verify.ExcelValid;
import com.example.demo.common.Func;
import com.example.demo.common.Valid;
import lombok.SneakyThrows;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.web.multipart.MultipartFile;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;

public class ExcelValidValidator implements ConstraintValidator<ExcelValid, Object> {
    private String[] ruleList;
    private String[] nameList;
    private boolean[] emptyList;

    @Override
    public void initialize(ExcelValid param) {
        this.ruleList = param.rule();
        this.nameList = param.name();
        this.emptyList = param.empty();

        if (this.emptyList == null || this.emptyList.length == 0) {
            this.emptyList = new boolean[this.nameList.length];
            Arrays.fill(this.emptyList, false);
        }
    }

    @SneakyThrows
    @Override
    public boolean isValid(Object obj, ConstraintValidatorContext context) {
        // 设置校验出错提示
        context.disableDefaultConstraintViolation();

        // 文件对象不能为null
        if (obj == null) {
            context.buildConstraintViolationWithTemplate("文件对象不能为空").addConstraintViolation();
            return false;
        }

        // 文件对象转换
        MultipartFile multipartfile;
        try {
            multipartfile = (MultipartFile)obj;
        }
        catch (Exception ex) {
            context.buildConstraintViolationWithTemplate("文件对象转换异常").addConstraintViolation();
            return false;
        }

        // 校验文件格式
        String fileExname = multipartfile.getOriginalFilename().substring(multipartfile.getOriginalFilename().lastIndexOf(".") + 1).toLowerCase();
        if (fileExname != null && !fileExname.isEmpty()) {
            if (!fileExname.equals("xls") && !fileExname.equals("xlsx")) {
                context.buildConstraintViolationWithTemplate("文件格式错误").addConstraintViolation();
                return false;
            }
        }
        else {
            context.buildConstraintViolationWithTemplate("文件格式错误").addConstraintViolation();
            return false;
        }

        // 获取表格
        File file = Func.getUploadFile(multipartfile);
        InputStream is = new FileInputStream(file);
        Workbook rwb = fileExname.equals("xls") ? new HSSFWorkbook(is) : new XSSFWorkbook(is);
        Sheet sheet = rwb.getSheetAt(0);
        int rows = sheet.getPhysicalNumberOfRows();
        Row row = sheet.getRow(0);
        int cols = row.getLastCellNum();

        // 校验表头数量是否一致
        if (this.nameList.length != cols) {
            context.buildConstraintViolationWithTemplate("表头格式错误或数量不一致").addConstraintViolation();
            return false;
        }

        // 校验表格内容
        for (int i = 1; i < rows; i++) {
            row = sheet.getRow(i);
            cols = row.getLastCellNum();

            /* 如果该行的列数小于表头数，且最后一列的规则不能为空，则说明最后一列的内容已经为空 */
            if (nameList.length != cols && !emptyList[cols - 1]) {
                context.buildConstraintViolationWithTemplate("第" + i + "行的" + this.nameList[cols - 1] + "不能为空").addConstraintViolation();
                return false;
            }

            for (int j = 0; j < cols; j++) {
                String message = "第" + i + "行的" + this.nameList[j] + "格式错误";
                String value = row.getCell(j).toString().trim();
                String[] rule = ruleList[j].split(",");

                if (!emptyList[j]) {
                    if (Valid.isEmpty(value)) {
                        context.buildConstraintViolationWithTemplate("第" + i + "行的" + this.nameList[j] + "不能为空").addConstraintViolation();
                        return false;
                    }
                }
                else {
                    if (Valid.isEmpty(value)) {
                        continue;
                    }
                }

                for (int m = 0; m < rule.length; m++) {
                    if (rule[m].contains("length")) {
                        int length = Integer.parseInt(rule[m].replace("length(", "").replace(")", ""));
                        if (value.length() > length) {
                            context.buildConstraintViolationWithTemplate(message).addConstraintViolation();
                            return false;
                        }
                    }
                    else if (rule[m].contains("select")) {
                        String select = rule[m].replace("select(", "").replace(")", "");
                        List<String> list = Arrays.asList(select.split("\\|"));
                        if (!list.contains(value)) {
                            context.buildConstraintViolationWithTemplate(message).addConstraintViolation();
                            return false;
                        }
                    }
                    else if (rule[m].contains("range")) {
                        String range = rule[m].replace("range(", "").replace(")", "");
                        int min = Integer.parseInt(range.split("-")[0]);
                        int max = Integer.parseInt(range.split("-")[1]);
                        if (!Valid.isNum(value) || Integer.parseInt(value) < min || Integer.parseInt(value) > max) {
                            context.buildConstraintViolationWithTemplate(message).addConstraintViolation();
                            return false;
                        }
                    }
                    else if (rule[m].contains("max")) {
                        int max = Integer.parseInt(rule[m].replace("max(", "").replace(")", ""));
                        if (!Valid.isNum(value) || Integer.parseInt(value) > max) {
                            context.buildConstraintViolationWithTemplate(message).addConstraintViolation();
                            return false;
                        }
                    }
                    else if (rule[m].contains("min")) {
                        int min = Integer.parseInt(rule[m].replace("min(", "").replace(")", ""));
                        if (!Valid.isNum(value) || Integer.parseInt(value) < min) {
                            context.buildConstraintViolationWithTemplate(message).addConstraintViolation();
                            return false;
                        }
                    }
                    else if (rule[m].contains("wick")) {
                        if (Valid.isWicked(value)) {
                            context.buildConstraintViolationWithTemplate(message).addConstraintViolation();
                            return false;
                        }
                    }
                    else if (rule[m].contains("contact")) {
                        if (!Valid.isContact(value)) {
                            context.buildConstraintViolationWithTemplate(message).addConstraintViolation();
                            return false;
                        }
                    }
                    else if (rule[m].contains("email")) {
                        if (!Valid.isEmail(value)) {
                            context.buildConstraintViolationWithTemplate(message).addConstraintViolation();
                            return false;
                        }
                    }
                    else if (rule[m].contains("mobile")) {
                        if (!Valid.isMobile(value)) {
                            context.buildConstraintViolationWithTemplate(message).addConstraintViolation();
                            return false;
                        }
                    }
                    else if (rule[m].contains("phone")) {
                        if (!Valid.isPhone(value)) {
                            context.buildConstraintViolationWithTemplate(message).addConstraintViolation();
                            return false;
                        }
                    }
                    else if (rule[m].contains("num")) {
                        if (!Valid.isNum(value)) {
                            context.buildConstraintViolationWithTemplate(message).addConstraintViolation();
                            return false;
                        }
                    }
                    else if (rule[m].contains("money")) {
                        if (!Valid.isMoney(value)) {
                            context.buildConstraintViolationWithTemplate(message).addConstraintViolation();
                            return false;
                        }
                    }
                    else if (rule[m].contains("date")) {
                        if (!Valid.isDate(value)) {
                            context.buildConstraintViolationWithTemplate(message).addConstraintViolation();
                            return false;
                        }
                    }
                    else {
                        context.buildConstraintViolationWithTemplate("校验规则错误").addConstraintViolation();
                        return false;
                    }
                }
            }
        }

        return true;
    }
}
